//
//  ViewController.m
//  GCDDemo
//
//  Created by zxs on 2020/4/28.
//  Copyright © 2020 zxs. All rights reserved.
//

#import "ViewController.h"
#import "SingleDemo.h"

@interface ViewController ()
// 基本使用
@property (weak, nonatomic) IBOutlet UIButton *baseButton;

// 任务组
@property (weak, nonatomic) IBOutlet UIButton *groupButton;

// 线程同步
@property (weak, nonatomic) IBOutlet UIButton *synchronizeButton;

// 延时执行
@property (weak, nonatomic) IBOutlet UIButton *delayButton;

// 定时器
@property (strong, nonatomic) dispatch_source_t timer;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
}

// 基本使用
- (IBAction)baseButtonTouched:(id)sender {
    self.baseButton.enabled = NO;
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        NSLog(@"global_queue执行耗时任务，这里sleep 5s");
        NSLog(@"%@", [NSThread currentThread]);
        sleep(5);
        dispatch_async(dispatch_get_main_queue(), ^{
            NSLog(@"回到main_queue，更新界面");
            NSLog(@"%@", [NSThread currentThread]);
            self.baseButton.enabled = YES;
        });
    });
}

// 死锁
- (IBAction)deadLockButtonTouched:(id)sender {
    NSLog(@"同步执行之前，这里是主线程");
    NSLog(@"%@", [NSThread currentThread]);
    dispatch_sync(dispatch_get_main_queue(), ^{
        NSLog(@"执行耗时任务，这里sleep 5s");
        NSLog(@"%@", [NSThread currentThread]);
        [NSThread sleepForTimeInterval:5];
    });
    NSLog(@"同步执行之后，主线程自己等自己，发生死锁，这里到不了。");
}

// 多读单写，栅栏函数
- (IBAction)barrierButtonTouched:(id)sender {
    // 将读写都放入同一个并行队列;注意，这里用dispatch_get_global_queue不行；
    dispatch_queue_t concurrentQueue = dispatch_queue_create("cn.com.zxs.GCDDemo", DISPATCH_QUEUE_CONCURRENT);
    
    // 写之前的读操作，并发执行
    dispatch_async(concurrentQueue, ^{
        NSLog(@"这是写之前的读操作1。");
    });
    
    dispatch_async(concurrentQueue, ^{
        NSLog(@"这是写之前的读操作2。");
    });
    
    dispatch_async(concurrentQueue, ^{
        NSLog(@"这是写之前的读操作3。");
    });
    
    // 写操作，在栅栏函数中，单独执行
    dispatch_barrier_async(concurrentQueue, ^{
        NSLog(@"这是写操作，在栅栏函数中。");
        [NSThread sleepForTimeInterval:1];
    });
    
    // 写之后的读操作，并发执行
    dispatch_async(concurrentQueue, ^{
        NSLog(@"这是写之后的读操作1。");
    });
    
    dispatch_async(concurrentQueue, ^{
        NSLog(@"这是写之后的读操作2。");
    });
    
    dispatch_async(concurrentQueue, ^{
        NSLog(@"这是写之后的读操作3。");
    });
}

// 任务组
- (IBAction)groupButtonTouched:(id)sender {
    // 网络任务开始前，修改界面
    self.groupButton.enabled = NO;
    NSLog(@"网络组下载任务开始了... ...");
    
    // 子任务都放入同一个并行队列，保证效率
    dispatch_queue_t concurrentQueue = dispatch_queue_create("cn.com.zxs.GCDDemo", DISPATCH_QUEUE_CONCURRENT);
    
    // 任务组
    dispatch_group_t group = dispatch_group_create();
    
    // 子任务派发;异步形式
    dispatch_group_async(group, concurrentQueue, ^{
        sleep(2);
        NSLog(@"完成子任务1");
    });
    
    dispatch_group_async(group, concurrentQueue, ^{
        sleep(1);
        NSLog(@"完成子任务2");
    });
    
    dispatch_group_async(group, concurrentQueue, ^{
        sleep(3);
        NSLog(@"完成子任务3");
    });
    
    // 子任务都完成后，更新界面等后续工作
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        NSLog(@"完成所有子任务，更新界面");
        self.groupButton.enabled = YES;
    });
}

// 线程同步
- (IBAction)synchronizeButtonTouched:(id)sender {
    // 同步任务开始前，修改界面
    self.synchronizeButton.enabled = NO;
    
    // 一开始，AB都没有完成，没有信号
    dispatch_semaphore_t semaphoreA = dispatch_semaphore_create(0);
    dispatch_semaphore_t semaphoreB = dispatch_semaphore_create(0);
    
    // ABC同时开始；异步执行的并行队列，保证效率
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        NSLog(@"任务A不需要等待，开始...");
        sleep(2);
        NSLog(@"任务A完成，设置semaphoreA");
        dispatch_semaphore_signal(semaphoreA);
    });
    
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        NSLog(@"任务B第1部分不需要等待，开始...");
        sleep(1);
        NSLog(@"任务B第1部分完成，等待任务A的完成信号semaphoreA");
        dispatch_semaphore_wait(semaphoreA, DISPATCH_TIME_FOREVER);
        NSLog(@"收到任务A完成的信号，任务B第2部分开始...");
        sleep(2);
        NSLog(@"任务B第2部分完成，设置semaphoreB");
        dispatch_semaphore_signal(semaphoreB);
        sleep(6);
        NSLog(@"任务B第3部分完成。耗时较长，估计排最后面了。");
    });
    
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        NSLog(@"要等任务B第2部分完成，任务C开始不了!!!!");
        dispatch_semaphore_wait(semaphoreB, DISPATCH_TIME_FOREVER);
        NSLog(@"任务B第2部分终于来了，任务C开始...");
        [NSThread sleepForTimeInterval:0.5];
        NSLog(@"任务C完成！");
        dispatch_async(dispatch_get_main_queue(), ^{
            NSLog(@"任务C负责更新界面，不管任务B第3部分！！！！");
            self.synchronizeButton.enabled = YES;
        });
    });
}

// 线程安全
- (IBAction)safeButtonTouched:(id)sender {
    // 值为1的semaphore相当于锁
    dispatch_semaphore_t lockSemaphore = dispatch_semaphore_create(1);
    // 钱只有一份，是大家公用的，需要加锁，保证线程安全
    __block NSInteger money = 1000;
    
    // 10个人同时来取钱
    for (int i = 0; i < 4; i++) {
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            NSLog(@"第%d个人开始操作，初始金额：%ld===", (i + 1), money);
            sleep(5);
            // 访问关键资源，用锁保护
            dispatch_semaphore_wait(lockSemaphore, DISPATCH_TIME_FOREVER);
            NSLog(@"第%d个人开始取钱；当前余额：%ld...", (i + 1), money);
            sleep(2);
            money -= 100;  // 每人每次取10元
            NSLog(@"第%d个人取钱完毕；当前余额：%ld", (i + 1), money);
            dispatch_semaphore_signal(lockSemaphore);
        });
    }
}

// 延时执行
- (IBAction)delayButtonTouched:(id)sender {
    NSLog(@"延时执行开始....");
    self.delayButton.enabled = NO;
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        NSLog(@"延时执行结束");
        self.delayButton.enabled = YES;
    });
}

// 单次执行
- (IBAction)onceButtonTouched:(id)sender {
    SingleDemo *single1 = [SingleDemo sharedInstance];
    NSLog(@"对象single1地址：%@", single1);
    
    SingleDemo *single2 = [SingleDemo sharedInstance];
    NSLog(@"对象single2地址：%@", single2);
    
    SingleDemo *single3 = [SingleDemo sharedInstance];
    NSLog(@"对象single3地址：%@", single3);
}

// 定时器
- (IBAction)timeButtonTouched:(id)sender {
    __block NSInteger index = 0;
    // 将定时器设置在并行队列，不影响主线程的界面
    self.timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0));
    dispatch_source_set_timer(self.timer, DISPATCH_TIME_NOW, 2 * NSEC_PER_SEC, 0 * NSEC_PER_SEC);
    dispatch_source_set_event_handler(self.timer, ^{
        index++;
        NSLog(@"定时器任务第%ld次执行", (long)index);
    });
    dispatch_resume(self.timer);
}

@end
